package com.project.springboot.aspect;

import com.gitee.yongzhuzl.commonutil.util.empty.EmptyUtil;
import com.gitee.yongzhuzl.commonutil.util.json.JsonUtil;
import com.gitee.yongzhuzl.commonutil.util.request.RequestUtil;
import com.project.springboot.annotation.Log;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * description: 自定义日志AOP切面
 * @author 朱正磊
 * @date 2025-05-12 14:37:05
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

    private final ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * description: 切点
     * @author 朱正磊
     * @date 2025-05-12 14:52:07
     */
    @Pointcut("@annotation(com.project.springboot.annotation.Log)")
    public void logPointcut() {}

    /**
     * description: 记录请求开始信息
     * @author 朱正磊
     * @date 2025-05-12 14:52:16
     * @param joinPoint 连接点
     */
    @Before("logPointcut()")
    public void before(JoinPoint joinPoint) {
        startTime.set(System.currentTimeMillis());

        // 获取当前请求
        HttpServletRequest request = RequestUtil.getRequest();

        // 获取方法上的注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Log logAnnotation = signature.getMethod().getAnnotation(Log.class);

        // 构建日志信息
        Map<String, Object> logInfo = new LinkedHashMap<>();
        logInfo.put("operation", logAnnotation.value());
        logInfo.put("requestMethod", request.getMethod());
        logInfo.put("requestUrl", request.getRequestURL().toString());
        logInfo.put("clientIp", request.getRemoteAddr());

        // 记录参数
        if (logAnnotation.recordParams()) {
            Object[] args = joinPoint.getArgs();
            if (EmptyUtil.isNotEmpty(args)) {
                logInfo.put("params", args);
            }
        }

        log.info("请求开始：{}", JsonUtil.toString(logInfo));
    }

    /**
     * description: 记录请求完成信息和返回结果
     * @author 朱正磊
     * @date 2025-05-12 14:52:25
     * @param joinPoint 连接点
     * @param result 返回结果
     */
    @AfterReturning(pointcut = "logPointcut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        // 获取方法上的注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Log logAnnotation = signature.getMethod().getAnnotation(Log.class);

        // 构建返回日志
        Map<String, Object> logInfo = new LinkedHashMap<>();
        logInfo.put("operation", logAnnotation.value());

        // 记录返回结果
        if (logAnnotation.recordResult()) {
            logInfo.put("result", result);
        }

        // 记录执行时间
        long endTime = System.currentTimeMillis();
        long executeTime = endTime - startTime.get();
        logInfo.put("executeTime", executeTime + "ms");

        log.info("请求完成：{}", JsonUtil.toString(logInfo));
        startTime.remove();
    }

    /**
     * description: 记录异常信息
     * @author 朱正磊
     * @date 2025-05-12 14:52:32
     * @param joinPoint 连接点
     * @param e 异常信息
     */
    @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Throwable e) {
        // 获取方法上的注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Log logAnnotation = signature.getMethod().getAnnotation(Log.class);

        // 构建异常日志
        Map<String, Object> logInfo = new LinkedHashMap<>();
        logInfo.put("operation", logAnnotation.value());
        logInfo.put("exception", e.getMessage());

        log.info("请求异常：{}", JsonUtil.toString(logInfo), e);
        startTime.remove();
    }

}
